package MapHelper

import (
	"errors"
	"fmt"
	"net/url"
	"reflect"
	"strconv"
	"strings"
)

/**
结构体转map
@param param 结构体 指针或非针
@param parseType 指定结构字属性 tag 字段 自定义

[example]
--------
type Maps struct {
  Data string `map:"data"`
  NumberName int `map:"number_name"`
}
mp:=Maps{
  Data:       "111",
  NumberName: 2,
}
a,_:=MapHelper.Struct2Map(mp, "map")
fmt.Printf("%+v",a)
--------
*/
func Struct2MapNoNil(param interface{}, parseType string) (map[string]interface{}, error) {
	if param == nil {
		return nil, errors.New(" param interface{} can not be nil")
	}
	if len(strings.TrimSpace(parseType)) == 0 {
		return nil, errors.New("parseType string can not be empty")
	}
	return Struct2Map(param, parseType), nil
}

func Struct2Map(param interface{}, parseType string) map[string]interface{} {
	if param == nil {
		return make(map[string]interface{})
	}
	if len(parseType) == 0 {
		parseType = "json"
	}
	ValueT := reflect.ValueOf(param)
	TypeT := reflect.TypeOf(param)
	if TypeT.Kind() == reflect.Ptr {
		TypeT = TypeT.Elem()
		ValueT = ValueT.Elem()
	}
	fatherMap := make(map[string]interface{})
	for i := 0; i < TypeT.NumField(); i++ {
		typei := TypeT.Field(i).Type
		if len(ValueT.Field(i).String()) > 0 {
			switch typei.Kind() {
			case reflect.Struct:
				fatherMap[TypeT.Field(i).Tag.Get(parseType)] = Struct2Map(ValueT.Field(i).Interface(), parseType)
				break
			case reflect.Bool:
				fatherMap[TypeT.Field(i).Tag.Get(parseType)] = ValueT.Field(i).Bool()
				break
			case reflect.Slice:
				fatherMap[TypeT.Field(i).Tag.Get(parseType)] = ValueT.Field(i).Interface()
				break
			case reflect.Int:
				fatherMap[TypeT.Field(i).Tag.Get(parseType)] = ValueT.Field(i).Int()
				break
			default:
				fatherMap[TypeT.Field(i).Tag.Get(parseType)] = ValueT.Field(i).String()
			}
		}
	}
	return fatherMap
}


func MapToUrlString(dataMap map[string]interface{}) string {
	if dataMap == nil {
		return "'"
	}
	param := url.Values{}
	for k, v := range dataMap {
		switch v.(type) {
		case int:
			param.Add(k, strconv.Itoa(v.(int)))
		case string:
			param.Add(k, v.(string))
		case float64:
			param.Add(k, fmt.Sprintf("%f", v.(float64)))
		}
	}
	return param.Encode()
}
